package com.cybertron.ironhide.search.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.FacetParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cybertron.ironhide.search.common.Constants;
import com.cybertron.ironhide.search.common.base.Pager;
import com.cybertron.ironhide.search.domain.Article;
import com.cybertron.ironhide.search.domain.Category;
import com.cybertron.ironhide.search.domain.Product;
import com.cybertron.ironhide.search.persistence.ArticleMapper;
import com.cybertron.ironhide.search.persistence.CategoryMapper;
import com.cybertron.ironhide.search.persistence.ProductMapper;
import com.cybertron.ironhide.search.service.ProductService;
import com.cybertron.ironhide.search.util.SolrUtil;
import com.cybertron.ironhide.search.util.SuggestUtil;

@Service
public class ProductServiceImpl implements ProductService {

	@Autowired(required = false)
	private ProductMapper productMapper;

	@Autowired(required = false)
	private CategoryMapper categoryMapper;

	@Autowired(required = false)
	private ArticleMapper articleMapper;

	@Autowired(required = false)
	private SolrServer solrServer;

	@Override
	public Map<String, Object> search(String keyWord,
			Map<String, String> filters, Pager pager) {
		SolrQuery query = new SolrQuery();
		query.setParam(FacetParams.FACET, "on");
		query.setParam(FacetParams.FACET_LIMIT, "15");
		query.add(FacetParams.FACET_FIELD, "{!ex=source}source");
		query.add(FacetParams.FACET_FIELD, "{!ex=categoryId}categoryId");
		query.add(FacetParams.FACET_FIELD, "{!ex=tagF}tag");
		query.add(FacetParams.FACET_MISSING, "on");

		List<String> terms = SuggestUtil.suggest(keyWord);

		List<Article> topArticles = articleMapper.selectTop(
				Constants.TOP_ARTICLE_TYPE, Constants.TOP_ARTICLE_COUNT - 1);
		List<Article> botArticles = articleMapper.selectTop(
				Constants.BOT_ARTICLE_TYPE, Constants.BOT_ARTICLE_COUNT);

		query.setStart((pager.getPageNum() - 1) * pager.getNumPerPage());
		query.setRows(pager.getNumPerPage());
		setQueryParams(query, keyWord, filters);
		QueryResponse response = null;

		try {
			response = solrServer.query(query);
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

		List<Product> products = getProduct(response);
		Map<String, Object> tags = getTags(response, "all");
		pager.setTotalCount(response.getResults().getNumFound());
		Map<String, Object> results = new HashMap<String, Object>();
		results.put("products", products);
		results.put("terms", terms);
		results.put("topArticles", topArticles);
		results.put("botArticles", botArticles);
		results.putAll(tags);
		return results;
	}

	private void setQueryParams(SolrQuery query, String keyWord,
			Map<String, String> filters) {
		if (StringUtils.isNotBlank(keyWord)) {
			query.setQuery(SolrUtil.transformToSolr(keyWord));
			query.setParam("defType", "dismax");
			query.setParam("qf", "title");
			query.setParam("mm", "2");
		} else {
			query.setQuery("*:*");
		}
		if (filters == null) {
			return;
		}

		Double highPrice = 2000000d;
		Double lowPrice = 0d;

		for (String key : filters.keySet()) {
			if ("filterCategoryId".equals(key)) {
				List<String> childs = getChildIds(null, filters.get(key));
				String cateQuery = null;
				if (childs != null && childs.size() != 0) {
					String[] childIds = new String[childs.size()];
					childs.toArray(childIds);
					if (StringUtils.isBlank(keyWord)
							&& MapUtils.getString(filters, "filterCategoryId") != null) {
						cateQuery = "categoryId:(\""
								+ StringUtils.join(childIds, "\",\"") + "\")";
						query.setQuery(cateQuery);
					} else {
						cateQuery = "{!tag=categoryId}categoryId:(\""
								+ StringUtils.join(childIds, "\",\"") + "\")";
						query.addFilterQuery(cateQuery);
					}
				} else {
					if (StringUtils.isBlank(keyWord)
							&& MapUtils.getString(filters, "filterCategoryId") != null) {
						cateQuery = "categoryId:" + "\"" + filters.get(key)
								+ "\"";
						query.setQuery(cateQuery);
					} else {
						cateQuery = "{!tag=categoryId}categoryId:" + "\""
								+ filters.get(key) + "\"";
						query.addFilterQuery(cateQuery);
					}
				}

			}
			if ("filterKeyWords".equals(key)) {
				if (StringUtils.isNotBlank(MapUtils.getString(filters,
						"filterKeyWords"))) {
					query.addFilterQuery("title:" + "\"" + filters.get(key)
							+ "\"");
				}
			}
			if ("filterShipping".equals(key)) {
				if ("true".equals(filters.get(key))) {
					query.addFilterQuery("freeShipping:" + filters.get(key));
				}
			}
			if ("filterPrice".equals(key)) {
				if ("-".equals(filters.get(key))) {
					continue;
				}
				try {
					lowPrice = Double.valueOf(StringUtils.substringBefore(
							filters.get(key), "-"));
				} catch (NumberFormatException e) {
					e.printStackTrace();
					lowPrice = 0d;
				}
				try {
					highPrice = Double.valueOf(StringUtils.substringAfter(
							filters.get(key), "-"));
				} catch (NumberFormatException e) {
					e.printStackTrace();
					highPrice = 2000000d;
				}
				if (highPrice == 0 && lowPrice == 0) {
					continue;
				}

				if (lowPrice > highPrice) {
					Double highPriceTem = highPrice;
					highPrice = lowPrice;
					lowPrice = highPriceTem;
				}
				query.addFilterQuery("price:[" + lowPrice + " TO " + highPrice
						+ "]");

			}
			if ("filterSort".equals(key)) {
				String sortValue = filters.get(key);
				if ("asc".equals(sortValue)) {
					query.setSort("price", ORDER.asc);
				}
				if ("desc".equals(sortValue)) {
					query.setSort("price", ORDER.desc);
				}
			}
			if ("filterSource".equals(key)) {
				query.addFilterQuery("{!tag=source}source:" + "\""
						+ filters.get(key) + "\"");
			}
			if ("filterTag".equals(key)) {
				query.addFilterQuery("{!tag=tagF}tag:" + "\""
						+ SolrUtil.transformToSolr(filters.get(key)) + "\"");
			}
		}
		if (lowPrice != 0) {
			filters.put("lowPrice", lowPrice.toString());
		}
		if (highPrice != 2000000d) {
			filters.put("highPrice", highPrice.toString());
		}
	}

	private List<String> getChildIds(List<String> categories, String parentId) {
		if (categories == null) {
			categories = new ArrayList<String>();
		}
		List<Category> childs = categoryMapper.selectChilds(parentId, null);
		for (Category cate : childs) {
			if (cate.getIsFinal()) {
				categories.add(cate.getId());
			} else {
				getChildIds(categories, cate.getId());
			}
		}
		return categories;
	}

	@Override
	public List<Category> getSiteMap(String categoryId) {
		if (StringUtils.isBlank(categoryId)) {
			return null;
		}
		Category category = categoryMapper.selectByPrimaryKey(categoryId);
		String treePath = null;
		if (category != null) {
			treePath = category.getTreePath();
		}
		List<Category> categories = categoryMapper
				.selectSiteMapByTreePath(StringUtils.split(treePath, ","));
		return categories;
	}

	@Override
	public Map<String, Object> getTags(String keyWord, String categoryId,
			String type) {
		SolrQuery query = new SolrQuery();
		query.setParam(FacetParams.FACET, "on");
		query.setParam(FacetParams.FACET_LIMIT, "11");
		query.add(FacetParams.FACET_FIELD, type);
		query.add(FacetParams.FACET_MISSING, "on");
		if (StringUtils.isNotBlank(keyWord)) {
			query.setQuery(SolrUtil.transformToSolr(keyWord));
			query.setParam("defType", "dismax");
			query.setParam("qf", "title");
			query.setParam("mm", "2");
		} else {
			query.setQuery("*:*");
		}
		Map<String, String> filters = null;
		if (StringUtils.isNotBlank(categoryId)) {
			filters = new HashMap<String, String>();
			filters.put("filterCategoryId", categoryId);
		}
		setQueryParams(query, keyWord, filters);
		QueryResponse response = null;

		try {
			response = solrServer.query(query);
		} catch (SolrServerException e) {
			e.printStackTrace();
		}
		return getTags(response, type);
	}

	public Map<String, Object> getTags(QueryResponse response, String type) {
		Map<String, Object> results = new HashMap<String, Object>();

		List<Category> categories = null;
		List<String> tags = null;
		List<String> sources = null;
		List<Category> siteMaps = null;

		List<FacetField> facetFields = response.getFacetFields();
		if (facetFields != null && facetFields.size() != 0) {
			for (FacetField facetField : facetFields) {
				if (("all".equals(type) || "categoryId".equals(type))
						&& "categoryId".equals(facetField.getName())) {
					categories = new ArrayList<Category>();
					List<Count> counts = facetField.getValues();
					for (Count count : counts) {
						if (count.getName() == null || count.getCount() == 0) {
							continue;
						}
						Category category = categoryMapper
								.selectByPrimaryKey(count.getName());
						if (category != null) {
							categories.add(category);
						}
					}
					results.put("categories", categories);
				}
				if (("all".equals(type) || "tag".equals(type))
						&& "tag".equals(facetField.getName())) {
					tags = new ArrayList<String>();
					List<Count> counts = facetField.getValues();
					for (Count count : counts) {
						if (count.getName() == null || count.getCount() == 0) {
							continue;
						}
						tags.add(StringUtils.capitalize(count.getName()));
					}
					results.put("tags", tags);
				}
				if (("all".equals(type) || "source".equals(type))
						&& "source".equals(facetField.getName())) {
					sources = new ArrayList<String>();
					List<Count> counts = facetField.getValues();
					for (Count count : counts) {
						if (count.getCount() == 0) {
							continue;
						}
						sources.add(count.getName());
					}
					results.put("sources", sources);
				}
			}
		}
		if (categories != null && categories.size() != 0) {
			siteMaps = getSiteMap(categories.get(0).getId());
			results.put("siteMaps", siteMaps);
		}
		return results;
	}

	private List<Product> getProduct(QueryResponse response) {
		SolrDocumentList docs = response.getResults();
		List<Product> products = null;
		if (docs != null && docs.size() != 0) {
			products = new ArrayList<Product>();
		} else {
			return null;
		}
		Map<String, Map<String, List<String>>> highlights = response
				.getHighlighting();

		for (SolrDocument doc : docs) {
			Product product = new Product();
			product.setId((String) doc.get("id"));
			product.setTitle((String) doc.get("title"));
			product.setGroupId((String) doc.get("groupId"));
			product.setSource((String) doc.get("source"));
			product.setImage((String) doc.get("image"));
			product.setPrice((Double) doc.get("price"));
			product.setListPrice((Double) doc.get("listPrice"));
			product.setLowestPrice((Double) doc.get("lowestPrice"));
			product.setHighestPrice((Double) doc.get("highestPrice"));
			product.setSummary(StringUtils.lowerCase((String) doc
					.get("summary")));
			product.setFreeShipping((Boolean) doc.get("freeShipping"));
			product.setTargetUrl((String) doc.get("targetUrl"));
			product.setDescription((String) doc.get("description"));
			Map<String, List<String>> highResult = highlights.get(product
					.getId());
			if (highlights != null && highResult.get("title") != null) {
				StringBuffer titles = new StringBuffer();
				for (String title : highResult.get("title")) {
					titles.append(title);
				}
				product.setTitle(titles.toString());
			}
			if (highlights != null && highResult.get("summary") != null) {
				StringBuffer summaries = new StringBuffer();
				for (String summary : highResult.get("summary")) {
					summaries.append(summary);
				}
				product.setSummary(summaries.toString());
			}
			products.add(product);
		}
		return products;
	}

	@Override
	public Product selectByPrimaryKey(String id) {
		return productMapper.selectByPrimaryKey(id);
	}

	@Override
	public Map<String, String> selectRd(String id) {
		return productMapper.selectRd(id);
	}

	@Override
	public List<Product> selectByGroupId(String id) {
		return productMapper.selectByGroupId(id);
	}

	@Override
	public Product selectByPrimaryKeyWithGroup(String groupId) {
		return productMapper.selectByPrimaryKeyWithGroup(groupId);
	}

}
